package luacompiler;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

import luafrontend.exceptions.LuaSemanticException;
import luafrontend.gen.ast.Chunk;
import luafrontend.gen.parser.LuaParser;
import luafrontend.gen.parser.ParseException;
import luafrontend.interpreter.InterpreterState;
import luafrontend.values.LuaFunction;
import luafrontend.values.LuaNumber;
import luafrontend.values.LuaReturnValue;
import luafrontend.values.LuaString;
import luafrontend.values.LuaTable;
import luafrontend.values.LuaValue;

public class LuaCompiler {

	/**
	 * @param args
	 * @throws FileNotFoundException 
	 * @throws ParseException 
	 */
	public static void main(String[] args) throws FileNotFoundException, ParseException {
		LuaParser parser = new LuaParser(new FileInputStream("test/test.lua"));
		parser.enable_tracing();
		Chunk chunk = parser.Start();
		
		System.out.println("AST:");
		StringBuffer buffer = new StringBuffer();
		chunk.prettyPrint(buffer, "");
		System.out.println(buffer);
		System.out.println();
		
		LuaTable globalEnv = new LuaTable();
		insertDebugFunctions(globalEnv);
		System.out.println("Global environment");
		System.out.println(globalEnv.toString());
		System.out.println();
		
		chunk.resolveNames();
		
		InterpreterState state = new InterpreterState();
		
		try {
			System.out.println("Program output");
			chunk.interpret(state, globalEnv);
			System.out.println();
		}
		catch (LuaSemanticException e) {
			System.err.print("Lua runtime error: ");
			System.err.println(e.getMessage());
			System.err.println();
			
			System.err.println("Lua stack trace:");
			state.printCallStack(System.err, "        at ");
			System.err.println();
			
			System.err.println("Java stack trace:");
			e.printStackTrace();
			System.err.println();
		}
	}

	static void insertDebugFunctions(LuaTable env) {
		env.set(new LuaString("print"), new LuaFunction() {
			@Override
			public LuaReturnValue call(List<LuaValue> args) {
				System.out.println(args.get(0).asString().getString());
				return new LuaReturnValue();
			}
		});
		
		env.set(new LuaString("readline"), new LuaFunction() {
			@Override
			public LuaReturnValue call(List<LuaValue> args) {
				LuaReturnValue val = new LuaReturnValue();
				try {
					val.add(new LuaString(new BufferedReader(new InputStreamReader(System.in)).readLine()));
				} catch (IOException e) {
				}
				return val;
			}
		});
		
		env.set(new LuaString("testret3"), new LuaFunction() {
			@Override
			public LuaReturnValue call(List<LuaValue> args) {
				LuaReturnValue val = new LuaReturnValue();
				val.add(new LuaNumber(0.5));
				val.add(new LuaNumber(2));
				val.add(new LuaString("hello"));
				return val;
			}
		});
		
		env.set(new LuaString("clock"), new LuaFunction() {
			@Override
			public LuaReturnValue call(List<LuaValue> args) {
				double secs = System.nanoTime() * 1e-9;
				
				LuaReturnValue val = new LuaReturnValue();
				val.add(new LuaNumber(secs));
				return val;
			}
		});
	}
}
